package dtos;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import services.book.AuthorService;
import services.book.BookService;
import services.book.PublisherService;

import books.Author;
import books.BookInfo;
import books.Publisher;

import com.juancavallotti.jdto.DTOBinder;
import com.juancavallotti.jdto.DTOBinderFactory;

/**
 * The factory class that creates a Transfer Object for a given EJB.
 */
public class FactoryDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    @Autowired
    private AuthorService authorService;

    @Autowired
    private PublisherService publisherService;

    @Autowired
    private BookService bookService;

    private DTOBinder binder;

    public AuthorService getAuthorService() {
        return this.authorService;
    }

    public void setAuthorService(final AuthorService authorService) {
        this.authorService = authorService;
    }

    public PublisherService getPublisherService() {
        return this.publisherService;
    }

    public void setPublisherService(final PublisherService publisherService) {
        this.publisherService = publisherService;
    }

    public BookService getBookService() {
        return this.bookService;
    }

    public void setBookService(final BookService bookService) {
        this.bookService = bookService;
    }

    public DTOBinder getBinder() {
        return this.binder;
    }

    public void setBinder(final DTOBinder binder) {
        this.binder = binder;
    }

    public FactoryDTO() {
        this.binder = DTOBinderFactory.getBinder();
    }

    public <T> List<T> toDtos(final Class<T> dtoClass, final List modelObjects) {
        return this.binder.bindFromBusinessObjectList(dtoClass, modelObjects);
    }

    public <T> T toDto(final Class<T> dtoClass, final Object modelObject) {
        return this.binder.bindFromBusinessObject(dtoClass, modelObject);
    }

    public <T> T toModel(final Class<T> modelClass, final Object dto) {
        return this.binder.extractFromDto(modelClass, dto);
    }

    public AuthorsDTO authorsToDto(final List<Author> authors) {
        AuthorsDTO dto = new AuthorsDTO();
        List<String> names = new ArrayList<String>();

        for (Author author : authors) {
            names.add(author.getName());
        }
        dto.setNames(names);
        return dto;
    }

    public PublishersDTO publishersToDto(final List<Publisher> publishers) {
        PublishersDTO dto = new PublishersDTO();
        List<String> names = new ArrayList<String>();

        for (Publisher publisher : publishers) {
            names.add(publisher.getName());
        }
        dto.setNames(names);
        return dto;
    }

    public BookInfo bookInfoDtoToModel(final BookInfoDTO dto) {
        BookInfo result = this.binder.extractFromDto(BookInfo.class, dto);

        List<AuthorDTO> authors = dto.getAuthors();
        List<Author> persistedAuthors = new ArrayList<Author>();
        for (AuthorDTO author : authors) {
            Author persisted = this.getAuthorService().findById(Author.class, author.getId());
            persistedAuthors.add(persisted);
        }
        if (dto.getPublisher() != null) {
            Publisher persistedPublisher = this.getPublisherService().findById(dto.getPublisher().getId());
            result.setPublisher(persistedPublisher);
        }

        result.setAuthors(persistedAuthors);
        return result;
    }

    public BookInfo bookInfoDtoToModel(final BookInfoDTO dto, final BookInfo aBookInfo) {
        aBookInfo.setTitle(dto.getTitle());
        aBookInfo.setAvailable(dto.isAvailable());

        aBookInfo.setCategories(dto.getCategories());
        aBookInfo.setDescription(dto.getDescription());
        aBookInfo.setIsbn(dto.getIsbn());

        List<AuthorDTO> authors = dto.getAuthors();
        List<Author> persistedAuthors = new ArrayList<Author>();
        for (AuthorDTO author : authors) {
            Author persisted = this.getAuthorService().findById(Author.class, author.getId());
            persistedAuthors.add(persisted);
        }
        Publisher persistedPublisher = this.getPublisherService().findById(dto.getPublisher().getId());

        aBookInfo.setPublisher(persistedPublisher);
        aBookInfo.setAuthors(persistedAuthors);
        return aBookInfo;
    }

}
